/** 
 * Project Name: farm-core 
 * File Name: Frame.java 
 * Package Name: com.bugull.farm.core.frame 
 * Date: 2017年2月21日下午5:08:49 
 * Copyright (c) 2017, hadlinks All Rights Reserved. 
 * 
 */
package com.bugull.farm.core.frame.structure;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.logging.log4j.*;

import com.bugull.farm.core.cache.PropertiesCache;
import com.bugull.farm.core.cache.ProtocolCache;
import com.bugull.farm.core.frame.exception.BuguException;
import com.bugull.farm.core.utils.ByteUtil;
import com.sun.prism.impl.BufferUtil;

/** 
 * ClassName: Frame 
 * Function: 自定义的消息结构，由ByteBuf转化而来，内部提供各种消息参数的提取和设值接口，可根据定义好的响应消息快速回复. 
 * date: 2017年2月21日 下午5:08:49  
 * 
 * @author songwei (songw@hadlinks.com)
 * @version 
 * @since JDK 1.8 
 */
public class Frame {

	protected Map<String, Object> requestMap = new HashMap<String, Object>();
	protected Map<String, Object> responseMap = new HashMap<String, Object>();
	protected String cmdType = "";
	protected String request = "";
	protected String response="";
	protected List<Param> reqList;
	protected List<Param> resList;
	protected List<Param> headList;
	private final Logger logger = LogManager.getLogger(Frame.class);
	private int cmdIndex;
	
	/**
	 * 构造函数
	 * @param msg
	 * @return
	 */
	public Frame(ByteBuf msg) throws Exception{
		//加载公共的协议头部分
		loadHead(msg);
		//加载请求命令Data部分，发送到服务器的命令有可能是主动上报的命令也有可能是某条命令的响应
		if(ByteUtil.getBit(getByte("flag"), 1)){
			loadResponse(msg);
		}else{
			loadRequest(msg);
		}
		this.resList = ProtocolCache.getInstance().getResponse(cmdType);
	}
	
	/**
	 * 加载协议公共部分内容，定义为协议头
	 * @param msg
	 */
	public void loadHead(ByteBuf msg){
		//根据命令类型找到head模板
		this.headList = ProtocolCache.getInstance().getHead();
		for(Param param : headList){
			int len = param.getLen();
			Object value = null;
			if(len == 1){
				value = msg.readByte();
			}else{
				byte[] temp = new byte[len];
				msg.readBytes(temp);
				value = temp;
			}
			if(param.isCmd()){
				this.cmdIndex = param.getIndex();
			}
			//map中的key统一成小写
			requestMap.put(param.getName().toLowerCase(), value);
			//map中的key统一成小写
			responseMap.put(param.getName().toLowerCase(), value);
		}
	}

	/**
	 * 加载xml模板中定义的协议命令响应部分
	 * @param msg
	 * @throws Exception
	 */
	public void loadResponse(ByteBuf msg) throws Exception{
		//根据命令类型找到response模板，并给responseMap赋值
		byte cmd = msg.getByte(cmdIndex);
		this.cmdType = ByteUtil.toHexString(cmd);
		this.resList = ProtocolCache.getInstance().getRequest(cmdType);
		//reqList为空表示没有该命令对应的协议模板文件
		if(resList == null){
			throw new BuguException(PropertiesCache.getInstance().getByte("error.cmd"), ByteBufUtil.getBytes(msg), "Unknow message type, cann't recognize the cmd !!!");
		}
		//reqList长度为0表示不需要解析该命令
		if(resList.size() == 0){
			response = ByteBufUtil.hexDump(msg);
			return;
		}
		for(Param param : resList){
			String type = param.getType();
			String name = param.getName().toLowerCase();
			if(type.equals("fixed")){//定长参数处理
				int len = param.getLen();
				Object value = null;
				if(len == 1){
					value = msg.readByte();
				}else{
					byte[] temp = new byte[len];
					msg.readBytes(temp);
					value = temp;
				}
				//map中的key统一成小写
				responseMap.put(name, value);
			}else{//变长参数处理
				String depend  = param.getDepend().toLowerCase();
				int len = 0;
				//找到depend
				if(responseMap.get(depend) != null){
					//判断是单字节数还是多字节数
					if(responseMap.get(depend) instanceof Byte){
						len = getUnsignedByte(depend);
					}else{
						len = getUnsignedInt(depend);
					}
				}
				if(len != 0){//上述获取len的步骤成功
					Object value = null;
					if(len == 1){
						value = msg.readByte();
					}else{
						byte[] temp = new byte[len];
						msg.readBytes(temp);
						value = temp;
					}
					//map中的key统一成小写
					responseMap.put(name, value);
				}else{//上述获取len的步骤失败
					logger.error("There is no depend param " + depend + " for param "+name + " !!!");
				}
			}
		}
		response = ByteBufUtil.hexDump(msg);
	}
	
	/**
	 * 加载xml模板中定义的协议命令请求部分内容
	 * @param msg
	 * @throws Exception
	 */
	public void loadRequest(ByteBuf msg)  throws Exception{
		//根据命令类型找到request模板，并给requestMap赋值
		byte cmd = msg.getByte(cmdIndex);
		this.cmdType = ByteUtil.toHexString(cmd);
		this.reqList = ProtocolCache.getInstance().getRequest(cmdType);
		//reqList为空表示没有该命令对应的协议模板文件
		if(reqList == null){
			throw new BuguException(PropertiesCache.getInstance().getByte("error.cmd"), ByteBufUtil.getBytes(msg), "Unknow message type, cann't recognize the cmd !!!");
		}
		//reqList长度为0表示不需要解析该命令
		if(reqList.size() == 0){
			request = ByteBufUtil.hexDump(msg);
			return;
		}
		for(Param param : reqList){
			String type = param.getType();
			String name = param.getName().toLowerCase();
			if(type.equals("fixed")){//定长参数处理
				int len = param.getLen();
				Object value = null;
				if(len == 1){
					value = msg.readByte();
				}else{
					byte[] temp = new byte[len];
					msg.readBytes(temp);
					value = temp;
				}
				//map中的key统一成小写
				requestMap.put(name, value);
			}else{//变长参数处理
				String depend  = param.getDepend().toLowerCase();
				int len = 0;
				//找到depend
				if(requestMap.get(depend) != null){
					//判断是单字节数还是多字节数
					if(requestMap.get(depend) instanceof Byte){
						len = getUnsignedByte(depend);
					}else{
						len = getUnsignedInt(depend);
					}
				}
				if(len != 0){//上述获取len的步骤成功
					Object value = null;
					if(len == 1){
						value = msg.readByte();
					}else{
						byte[] temp = new byte[len];
						msg.readBytes(temp);
						value = temp;
					}
					//map中的key统一成小写
					requestMap.put(name, value);
				}else{//上述获取len的步骤失败
					logger.error("There is no depend param " + depend + " for param "+name + " !!!");
				}
			}
		}
		request = ByteBufUtil.hexDump(msg);
	}
	
	public Map<String, Object> getRequestMap() {
		return requestMap;
	}

	public void setRequestMap(Map<String, Object> requestMap) {
		this.requestMap = requestMap;
	}

	public Map<String, Object> getResponseMap() {
		return responseMap;
	}

	public void setResponseMap(Map<String, Object> responseMap) {
		this.responseMap = responseMap;
	}

	public String getCmdType() {
		return cmdType;
	}

	public void setCmdType(String cmdType) {
		this.cmdType = cmdType;
	}

	public byte[] getRequest() {
		return ByteUtil.parseHexStringToArray(request);
	}
	
	public String getHexRequest() {
		return request;
	}

	public void setRequest(String request) {
		this.request = request;
	}


	public String getResponse() {
		return response;
	}


	public void setResponse(String response) {
		this.response = response;
	}
	
	/**
	 * 从requestMap中获取byte类型的参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public byte getByte(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			return (byte)requestMap.get(name);
		}else{
			throw new Exception("Cann't cast "+name+" from "+obj.getClass().getSimpleName()+" to byte!!!");
		}
	}
	
	/**
	 * 从requestMap中获取byte[]类型的参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public byte[] getBytes(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof byte[]){
			return (byte[])requestMap.get(name);
		}else{
			throw new Exception("Cann't cast "+name+" from "+obj.getClass().getSimpleName()+" to byte[]!!!");
		}
	}
	
	/**
	 * 从map中获取16进制字符形式的元素
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public String getHexStr(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			return ByteUtil.toHexString((byte)requestMap.get(name));
		}else if(obj instanceof byte[]){
			return ByteUtil.toHexString((byte[])requestMap.get(name));
		}
		return null;
	}
	
	/**
	 * 从map中获取ASCII码字符形式的元素
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public String getASCIIStr(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			throw new Exception("Cann't cast "+name+" from byte to String!!!");
		}else if(obj instanceof byte[]){
			return new String((byte[])requestMap.get(name));
		}
		return null;
	}
	
	/**
	 * 返回BCD码格式的int型参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public int getBCDInt(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			return Integer.parseInt(ByteUtil.toHexString((byte)obj));
		}else{
			return Integer.parseInt(ByteUtil.toHexString((byte[])obj));
		}
	}
	
	/**
	 * 
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public int getUnsignedByte(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			return (byte)obj & 0xFF;
		}else{
			throw new Exception("Unrecognize value for "+name+"!!!");
		}
	}
	
	/**
	 * 获取参数中无符号short型的参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public int getUnsignedShort(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof byte[]){
			return ByteUtil.toShort((byte[])obj) & 0xFFFF;
		}else{
			throw new Exception("Unrecognize value for "+name+"!!!");
		}
	}
	
	/**
	 * 获取map中无符号int类型的参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public Integer getUnsignedInt(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if (obj instanceof byte[]){
			byte[] a = (byte[])obj;
			int len = a.length;
			if(len < 1){
				throw new Exception("Cann't cast null to int!!!");
			}
			int result = (int) (len - 4 >= 0?a[len - 4]:0x00) << 24 |
					(len - 3 >= 0?a[len - 3]:0x00) << 16 | 
					(len - 2 >= 0?a[len - 2]:0x00) << 8 | 
					(len - 1 >= 0?a[len - 1]:0x00) ;
			return result;
		}else{
			throw new Exception("Cann't recognize the value type for "+name+"!!!");
		}
	}
	
	/**
	 * 从map中获取int类型的参数
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public int getInt(String name) throws Exception{
		name = name.toLowerCase();
		if(!requestMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Object obj = requestMap.get(name);
		if(obj instanceof Byte){
			return (byte)obj;
		}else if (obj instanceof byte[]){
			byte[] a = (byte[])obj;
			int len = a.length;
			if(len < 1){
				throw new Exception("Cann't cast null to int!!!");
			}
			return (int) (len - 1 >= 0?a[len - 1]:0x00) |
					(len - 2 >= 0?a[len - 2]:0x00) << 8 | 
					(len - 3 >= 0?a[len - 3]:0x00) << 16 | 
					(len - 4 >= 0?a[len - 4]:0x00) << 24 ;
		}else{
			throw new Exception("Cann't recognize the value type for "+name+"!!!");
		}
	}
	
	/**
	 * 设置responseMap中参数的值，只接受byte或byte[]类型
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void set(String name, Object value) throws Exception{
		name = name.toLowerCase();
		final String localName = name;
		if(!responseMap.containsKey(name) || requestMap.get(name)==null){
			throw new Exception("There is no "+name+" exist in Frame!!!");
		}
		Optional<Param> first = resList.stream().filter(param -> param.getName().equals(localName)).findFirst();
		if(!first.isPresent()) { //如果没有找到name对应的元素
			throw new Exception("No such param "+name+" found in response module, please check the cmd"+cmdType+".xml!!!");
		}
		Param param = first.get();
		if(param.getType().equals("fixed")) { //定长元素，判断长度是否符合
			if(value instanceof Byte && param.getLen() == 1){
				responseMap.put(name, value);
			}else if(value instanceof byte[]){
				byte[] temp = (byte[])value;
				if(param.getLen() == temp.length){
					responseMap.put(name, value);
				}else{
					throw new Exception("Length mismatch Exception：\nCann't fill a "+temp.length+" bytes value into "+name+" which has a "+param.getLen()+"  bytes fixed length!!!");
				}
			}
		} else { //变长元素，直接赋值
			if(value instanceof Byte && param.getLen() == 1){
				responseMap.put(name, value);
			}else if(value instanceof byte[]){
				responseMap.put(name, (byte[])value);
			}
		}
	}
	
	/**
	 * 向responseMap里设置一个byte类型参数的值
	 * @param name
	 * @param value
	 */
	public void setByte(String name, byte value) throws Exception{
		if(getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen != 1){
				throw new Exception("Length mismatch Exception：\nCann't fill a single byte value into "+name+" which has a "+paramLen+"  bytes fixed length!!!");
			}
		}
		responseMap.put(name, value);
	}
	
	/**
	 * 向responseMap里设置一个byte[]类型参数的值
	 * @param name
	 * @param value
	 */
	public void setBytes(String name, byte[] value) throws Exception{
		if(getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen != value.length){
				throw new Exception("Length mismatch Exception：\nCann't fill a "+value.length+" bytes value into "+name+" which has a "+paramLen+"  bytes fixed length!!!");
			}
		}
		responseMap.put(name, value);
	}
	
	/**
	 * 向responseMap里设置一个byte类型参数的值
	 * 由int转化而来，如果value的真值部分超过一个字节，取低位
	 * @param name 参数名称
	 * @param value 参数值
	 */
	public void setByte(String name, int value) throws Exception{
		if(getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen != 1){
				throw new Exception("Lenght dismatch Exception：\nCann't use setByte() to fill a "+paramLen+" length "+name+" with a single byte value!!!");
			}
		}
		byte tmp = ByteUtil.fromInt(value)[3];
		responseMap.put(name, tmp);
	}
	
	/**
	 * 向responseMap里设置一个byte[]类型参数的值
	 * 由int转化而来，如果value的真值部分超过参数的长度，按低位优先取值 
	 * 如果value的真值部分不足参数的长度，抛出异常
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void setBytes(String name, int value) throws Exception{
		byte[] tmp = ByteUtil.fromInt(value);
		if (getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen > tmp.length){
				throw new Exception("Lenght dismatch Exception：\nCann't use this function to fill in a "+paramLen+" length "+name+" with a "+tmp.length+" bytes value!!!");
			}
			byte[] tmp1 = new byte[paramLen];
			System.arraycopy(tmp, tmp.length-paramLen, tmp1, 0, paramLen);
			responseMap.put(name, tmp1);
		} else {
			responseMap.put(name, tmp);
		}
		
	}
	
	/**
	 * 向responseMap中设置一个byte类型参数的值
	 * 由value字符经过ASCII编码转化而来
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void setASCIIByte(String name, String value) throws Exception{
		byte[] tmp = value.getBytes(PropertiesCache.getInstance().get("charset.utf8"));
		if (getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(tmp.length != 1 || paramLen != 1){
				throw new Exception("Lenght dismatch Exception：\nCann't use setASCIIByte() to fill a "+paramLen+" length "+name+" with a "+tmp.length+" length value!!!");
			}
		}
		responseMap.put(name, tmp[0]);
	}
	
	/**
	 * 向responseMap中设置一个byte[]类型参数的值
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void setASCIIBytes(String name, String value) throws Exception{
		byte[] tmp = value.getBytes(PropertiesCache.getInstance().get("charset.utf8"));
		if (getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(tmp.length != paramLen){
				throw new Exception("Lenght dismatch Exception：\nCann't use setASCIIBytes() to fill a "+paramLen+" length "+name+" with a "+tmp.length+" length value!!!");
			}
		}
		responseMap.put(name, tmp);
	}
	
	/**
	 * 向responseMap中设置一个byte类型参数的值
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void setHexByte(String name, String value) throws Exception{
		byte tmp = ByteUtil.parseHexString(value);
		if (getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen != 1){
				throw new Exception("Lenght dismatch Exception：\nCann't use setHexByte() to fill a "+paramLen+" length "+name+" with a single byte value!!!");
			}
		}
		responseMap.put(name, tmp);
	}
	
	/**
	 * 向responseMap中设置一个byte[]类型参数的值
	 * @param name
	 * @param value
	 * @throws Exception
	 */
	public void setHexBytes(String name, String value) throws Exception{
		byte[] tmp = ByteUtil.parseHexStringToArray(value);
		if (getResParamLen(name) != null) {
			int paramLen = getResParamLen(name);
			if(paramLen != tmp.length){
				throw new Exception("Lenght dismatch Exception：\nCann't use setHexBytes() to fill a "+paramLen+" length "+name+" with a "+tmp.length+" length value!!!");
			}
		}
		responseMap.put(name, tmp);
	}
	
	/**
	 * 根据参数名称，获取参数长度
	 * @param name
	 * @return paramLen
	 * @throws Exception
	 */
	public Integer getResParamLen(String name) throws Exception{
		Optional<Param> first = resList.stream().filter(param -> param.getName().equals(name)).findFirst();
		if(!first.isPresent()){
			throw new Exception("No such param "+name+" found in response module, please check the cmd"+cmdType+".xml!!!");
		}
		Param param = first.get();
		if(param.getType().equals("fixed")){
			return first.get().getLen();
		}
		return null;
	} 
	
	/**
	 * 通过设置responseMap中的参数，进行命令的快速回复
	 * @return buf
	 * @throws Exception
	 */
	public ByteBuf getFastResponse() throws Exception{
		//这里申明的buf为UnpooledHeapByteBuf，可以依赖jvm的GC进行回收，与netty的ByteBuf(PooledByteBuf)不同
		ByteBuf buf = Unpooled.buffer();
		int lenIndex = 0;
		for(Param param : headList){
			int len = param.getLen();
			if(len == 1){//单字节内容
				Object value = responseMap.get(param.getName().toLowerCase());
				if(value == null){
					value = requestMap.get(param.getName().toLowerCase());
					if(value == null){
						throw new Exception("Cann't make up a "+this.cmdType+" response due to a null value of "+param.getName() + "!!!");
					}
				}
				buf.writeByte((byte)value);
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}else{//字节数组内容
				Object value = responseMap.get(param.getName().toLowerCase());
				if(value == null){
					value = requestMap.get(param.getName().toLowerCase());
					if(value == null){
						throw new Exception("Cann't make up a "+this.cmdType+" response due to a null value of "+param.getName() + "!!!");
					}
				}
				buf.writeBytes((byte[])value);
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}
		}
		for(Param param : resList){
			int len = param.getLen();
			if(len == 1){//单字节内容
				Object value = responseMap.get(param.getName().toLowerCase());
				if(value == null){
					throw new Exception("Cann't make up a "+this.cmdType+" response due to a null value of "+param.getName() + "!!!");
				}
				buf.writeByte((byte)value);
			}else{//字节数组内容
				Object value = responseMap.get(param.getName().toLowerCase());
				buf.writeBytes((byte[])value);
			}
		}
		int responseLen = buf.readableBytes() - lenIndex;
		buf.setByte(lenIndex - 2, ByteUtil.fromInt(responseLen)[2]);
		buf.setByte(lenIndex - 1, ByteUtil.fromInt(responseLen)[3]);
		buf.setByte(1, buf.getByte(1) | 0x02);
		return buf;
	}
	
	/**
	 * 快速拼装一条服务器反馈错误信息指令
	 * @param errorCode
	 * @return buf
	 * @throws Exception
	 */
	public ByteBuf getErrorResponse(byte errorCode) throws Exception{
		//这里申明的buf为UnpooledHeapByteBuf，可以依赖jvm的GC进行回收，与netty的ByteBuf(PooledByteBuf)不同
		ByteBuf buf = Unpooled.buffer();
		int lenIndex = 0;
		for(Param param : headList){
			if(param.isCmd()){
				continue;
			}
			int len = param.getLen();
			if(len == 1){//单字节内容
				Object value = responseMap.get(param.getName().toLowerCase());
				if(value == null){
					value = requestMap.get(param.getName().toLowerCase());
					if(value == null){
						throw new Exception("Cann't make up a errorResponse due to a null value of "+param.getName() + "!!!");
					}
				}
				buf.writeByte((byte)value);
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}else{//字节数组内容
				Object value = responseMap.get(param.getName().toLowerCase());
				if(value == null){
					value = requestMap.get(param.getName().toLowerCase());
					if(value == null){
						throw new Exception("Cann't make up a errorResponse due to a null value of "+param.getName() + "!!!");
					}
				}
				buf.writeBytes((byte[])value);
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}
		}
		buf.writeByte((byte)0xEE);
		buf.writeByte(ByteUtil.parseHexString(cmdType));
		buf.writeByte(errorCode);
		int responseLen = buf.readableBytes() - lenIndex;
		buf.setByte(lenIndex - 2, ByteUtil.fromInt(responseLen)[2]);
		buf.setByte(lenIndex - 1, ByteUtil.fromInt(responseLen)[3]);
		buf.setByte(1, buf.getByte(1) | 0x02);
		return buf;
	}
	
	
	/**
	 * 从当前frame下生成设备上线事件
	 * @return
	 * @throws Exception
	 */
	public ByteBuf getOnlineEvent() throws Exception{
		//这里申明的buf为UnpooledHeapByteBuf，可以依赖jvm的GC进行回收，与netty的ByteBuf(PooledByteBuf)不同
		ByteBuf buf = Unpooled.buffer();
		int lenIndex = 0;
		int authCodeIndex = 0;
		PropertiesCache props = PropertiesCache.getInstance();
		byte cmd = props.getByte("onlineEvent");
		byte online = props.getByte("val.dev.online");
		for(Param param : headList){
			if(param.isCmd()){
				continue;
			}
			int len = param.getLen();
			if(len == 1){//单字节内容
				Object value = requestMap.get(param.getName());
				if(value == null){
					throw new Exception("Cann't make up a onlineEvent due to a null value of "+param.getName() + "!!!");
				}
				buf.writeByte((byte)value);
				if(param.getName().equals("len")){
					lenIndex = buf.writerIndex();
				}
				if(param.getName().equals("authcode")){
					authCodeIndex = buf.writerIndex();
				}
			}else{//字节数组内容
				Object value = responseMap.get(param.getName());
				if(value == null){
					value = requestMap.get(param.getName());
					if(value == null){
						throw new Exception("Cann't make up a onlineEvent due to a null value of "+param.getName() + "!!!");
					}
				}
				buf.writeBytes((byte[])value);
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
				if(param.getName().toLowerCase().equals("authcode")){
					authCodeIndex = buf.writerIndex();
				}
			}
		}
		buf.writeByte(cmd);
		buf.writeByte(online);
		int onlineLen = buf.readableBytes() - lenIndex;
		buf.setByte(lenIndex - 2, ByteUtil.fromInt(onlineLen)[2]);
		buf.setByte(lenIndex - 1, ByteUtil.fromInt(onlineLen)[3]);
		buf.setBytes(authCodeIndex, new byte[]{0x00,0x00});
		return buf;
	}
	
	/**
	 * 从当前frame下生成查询命令
	 * @return
	 * @throws Exception
	 */
	public ByteBuf getQuery() throws Exception{
		//这里申明的buf为UnpooledHeapByteBuf，可以依赖jvm的GC进行回收，与netty的ByteBuf(PooledByteBuf)不同
		ByteBuf buf = Unpooled.buffer();
		int lenIndex = 0;
		int serialIndex = 0;
		PropertiesCache props = PropertiesCache.getInstance();
		byte cmd = props.getByte("queryEvent");
		for(Param param : headList){
			if(param.isCmd()){
				continue;
			}
			int len = param.getLen();
			if(len == 1){//单字节内容
				Object value = requestMap.get(param.getName());
				if(value == null){
					throw new Exception("Cann't make up a queryEvent due to a null value of "+param.getName() + "!!!");
				}
				if(param.getName().equals("serial")){
					serialIndex = buf.writerIndex();
				}
				buf.writeByte((byte)value);
				if(param.getName().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}else{//字节数组内容
				Object value = responseMap.get(param.getName());
				if(value == null){
					value = requestMap.get(param.getName());
					if(value == null){
						throw new Exception("Cann't make up a queryEvent due to a null value of "+param.getName() + "!!!");
					}
				}
				//写操作前记录index，获取serial的起始序号
				if(param.getName().equals("serial")){
					serialIndex = buf.writerIndex();
				}
				buf.writeBytes((byte[])value);
				//写操作后记录index，获取len的末位序号
				if(param.getName().toLowerCase().equals("len")){
					lenIndex = buf.writerIndex();
				}
			}
		}
		buf.writeByte(cmd);
		int onlineLen = buf.readableBytes() - lenIndex;
		//设置服务器协议序号
		buf.setBytes(serialIndex, props.getBytes("serial"));
		buf.setByte(lenIndex - 2, ByteUtil.fromInt(onlineLen)[2]);
		buf.setByte(lenIndex - 1, ByteUtil.fromInt(onlineLen)[3]);
		return buf;
	}
}
